/* arithmetic.cpp
Michael Zahniser, 12/12/09

Function definitions for the arithmetic operators.
*/

#include "Operators.h"

#include <cmath>

using std::string;

namespace {
	string Add = "add +";
	static const Do<Add> add;
	
	string Subtract = "subtract sub -";
	static const Do<Subtract> subtract;

	string Multiply = "multiply mul *";
	static const Do<Multiply> multiply;
	
	string Divide = "divide div /";
	static const Do<Divide> divide;
	
	string Modulus = "modulus mod %";
	static const Do<Modulus> mod;
	
	string Remainder = "remainder rem";
	static const Do<Remainder> remainder;

	string Negate = "negate neg _";
	static const Do<Negate> negate;
	
	string Invert = "invert inv \\";
	static const Do<Invert> invert;
	
	string Absolute = "absolute abs";
	static const Do<Absolute> absolute;
	
	string Ceiling = "ceiling ceil";
	static const Do<Ceiling> ceiling;
	
	string Floor = "floor";
	static const Do<Floor> floor;
	
	string Round = "round";
	static const Do<Round> round;
	
	string Truncate = "truncate trunc";
	static const Do<Truncate> truncate;
	
	string Fraction = "fraction frac";
	static const Do<Fraction> fraction;
}



template <> void Do<Add>::operator()(State &state) const
{
	state.Push(state.Pop() + state.Pop());
}



template <> void Do<Subtract>::operator()(State &state) const
{
	double b = state.Pop();
	state.Push(state.Pop() - b);
}



template <> void Do<Multiply>::operator()(State &state) const
{
	state.Push(state.Pop() * state.Pop());
}



template <> void Do<Divide>::operator()(State &state) const
{
	double b = state.Pop();
	state.Push(state.Pop() / b);
}



template <> void Do<Modulus>::operator()(State &state) const
{
	double b = state.Pop();
	state.Push(std::fmod(state.Pop(), b));
}



template <> void Do<Remainder>::operator()(State &state) const
{
	double b = state.Pop();
	double a = state.Pop();
	
	state.Push(std::floor(a / b));
	state.Push(std::fmod(a, b));
}



template <> void Do<Negate>::operator()(State &state) const
{
	state.Push(-state.Pop());
}



template <> void Do<Invert>::operator()(State &state) const
{
	state.Push(1. / state.Pop());
}



template <> void Do<Absolute>::operator()(State &state) const
{
	state.Push(std::fabs(state.Pop()));
}



template <> void Do<Ceiling>::operator()(State &state) const
{
	state.Push(std::ceil(state.Pop()));
}



template <> void Do<Floor>::operator()(State &state) const
{
	state.Push(std::floor(state.Pop()));
}



template <> void Do<Round>::operator()(State &state) const
{
	state.Push(std::floor(state.Pop() + .5));
}



template <> void Do<Truncate>::operator()(State &state) const
{
	state.Push(static_cast<long long>(state.Pop()));
}



template <> void Do<Fraction>::operator()(State &state) const
{
	state.Push(std::fmod(state.Pop(), 1.));
}
